Code to process Parekh paper data

This code is assembled to perform the steps to summarize differentially expressed genes and clusters of cells. The processed data were downloaded and saved in SEUSS_processed_data.

This cade has been pulled from https://github.com/yanwu2014/SEUSS-Analysis and specifically copied from hESC_summarize_results.R

The data for cells cultured in the pluripotent stem cell medium has been put into a compressed file in the Google Drive. You should be able to download it from the following link: https://drive.google.com/open?id=19qHsRFO4QwHhotxuw73MYRHB8CFYPM3c and extract the files onto your local computer. You will also need to change the file.handle appropriately (see below).

NOTE

The following packages must be installed prior to running (many needed only to load swne package. Uncomment to execute.

getPackageIfNeeded <- function(pkg) {
  if (!require(pkg, character.only=TRUE, quietly =TRUE))
    install.packages(pkgs=pkg, dependencies=TRUE)
}
getBiocPackageIfNeeded <- function(pkg, vers = NULL) {
  if (!require(pkg, character.only=TRUE, quietly =TRUE))
    BiocManager::install(pkgs=pkg, version=vers)
}

bcpkgs <- list(list(pkg="BiocManager",vers="3.10"),
               list(pkg="TxDb.Hsapiens.UCSC.hg38.knownGene",vers="3.10"),
               list(pkg="org.Hs.eg.db"),
               list(pkg="GO.db"),
               list(pkg="qvalue", vers="3.10")
               )

invisible(lapply(bcpkgs, function(x) 
    do.call(getBiocPackageIfNeeded, args=x)))

pkgs    <-  c("devtools","uwot","umap","Seurat")
invisible(sapply(pkgs,getPackageIfNeeded))
if (!require("NNLM")) 
  devtools::install_version("NNLM", version = "0.4.3")
if (!require("swne")) 
  devtools::install_github("yanwu2014/swne")
if (!require("perturbLM")) 
  devtools::install_github("yanwu2014/perturbLM", upgrade = "never")

Summary of steps to be run

Set the file.handle parameter to the name of the sample to be analyzed (this can include path information if data not in the same directory as this file). Generate a summary table for each sample, as well as cluster enrichment heatmaps, tSNE plots, and differential expression barplots.

The hESC_run_regression.R and hESC_run_clustering.R must have been run on the sample first. (This has already been done by Parekh et al.)

Step 1

Load all required libraries.

#### Create t-SNE plots, differential expression heatmaps, and cluster enrichment heatmaps
library(perturbLM)
library(swne)
library(ggplot2)
library(RColorBrewer)
library(Seurat)
library(grid)
library(gtable)
library(umap)

Step 2

Define file locations and load data. Example below includes path information for my computer. Must be modified to work appropriately on your computer.

## Name of the sample to be analyzed
file.handle <- "/Users/vagan/Downloads/Parekh_paper_data/up-tf-stem"
#file.handle <- "up-tf-stem"
# file.handle <- "up-tf-endo"
# file.handle <- "up-tf-multi"
# file.handle <- "up-tf-klf"
# file.handle <- "up-tf-myc"
# file.handle <- "up-tf-neuron-nohygro"

## Load regression results
coefs.df <- read.table(paste(file.handle, "regression.pvals.tsv", sep = "_"), sep = "\t", 
                       header = T, stringsAsFactors = F)
top.coefs.df <- subset(coefs.df, FDR < 0.05 & abs(cf) > 0.025)
print(sort(table(top.coefs.df$Group), decreasing = T))

            KLF4             CDX2            SNAI2          ONECUT1             MYOG 
             487              272              226              132              122 
           ASCL1          NEUROD1            MYOD1             TBX5              MYC 
             121              112              101               55               50 
           HNF1A            RUNX1          NEUROG3            ASCL4            MESP1 
              47               45               44               39               36 
         NEUROG1             LHX3            ASCL3             OTX2             SPI1 
              35               33               31               30               28 
          TFAP2C             SOX2             PAX7            FOXA3            ASCL5 
              27               23               22               20               19 
             CRX            HAND2            HOXA1             SPIC             SOX3 
              18               18               18               17               16 
           FOXA2            SOX10           HOXA11           POU1F1            GATA4 
              15               15               14               13               12 
            SIX2             ETV2            ESRRG            GATA2            HOXB6 
              11                9                6                6                5 
            SPIB            GATA1            MEF2C             MITF             SIX1 
               4                3                3                3                3 
             ERG           HOXA10            LMX1A mCherry-int-ctrl             MYCL 
               2                2                2                2                2 
             SRY             ATF7            FOXP1              NRL 
               2                1                1                1 
## Load clustering
r <- readRDS(paste(file.handle, "clustering.Robj", sep = "_"))


clusters <- r@ident; names(clusters) <- r@cell.names;
levels(clusters) <- paste("C", levels(clusters), sep = "")
clusters.list <- UnflattenGroups(clusters)

# update v2 Seurat object to v3
r <- UpdateSeuratObject(r)
Updating from v2.X to v3.X
Validating object structure
Updating object slots
Ensuring keys are in the proper strucutre
Ensuring feature names don't have underscores or pipes
Object representation is consistent with the most current Seurat version
## Load genotypes
# genotypes.list <- ReadGenotypes("up-tf-klf-myc_pheno_dict.csv")
genotypes.list <- ReadGenotypes(paste(file.handle, "pheno_dict.csv", sep = "_"))
genotypes.list <- lapply(genotypes.list, function(x) x[x %in% names(clusters)])
genotypes.sizes <- sapply(genotypes.list, length)

Step 3

Calculate enrichment scores and summarize results.

##  Calculate genotype enrichment
genotypes.cl.tbl <- GenotypeClusterCounts(genotypes.list, clusters.list)
genotypes.cl.pvals <- GenotypeClusterPvals(genotypes.cl.tbl)

genotypes.min.p <- apply(genotypes.cl.pvals, 1, function(x) min(abs(x)) * length(x))
metap::sumlog(genotypes.min.p)
Some studies omitted
chisq =  3750.279  with df =  118  p =  0 
## Summarize analysis results
genotype.counts <- sort(table(top.coefs.df$Group), decreasing = T)
genotype.counts <- genotype.counts[names(genotype.counts) %in% rownames(genotypes.cl.pvals)]
genotype.avg_cf <- tapply(top.coefs.df$cf, top.coefs.df$Group, function(x) mean(abs(x)))[names(genotype.counts)]

genotype.summary <- data.frame(n_diff_genes = as.integer(genotype.counts), avg_cf = genotype.avg_cf)
genotype.summary$min_cluster_pval <- apply(genotypes.cl.pvals[rownames(genotype.summary), ], 1, function(x) min(abs(x)))
genotype.summary$min_cluster <- apply(genotypes.cl.pvals[rownames(genotype.summary), ], 1, function(x) names(x[which.min(abs(x))]))
genotype.summary$n_cells <- genotypes.sizes[rownames(genotype.summary)]

Uncomment code below if you want to save the output data to a file.

# write.table(genotype.summary, file = paste(file.handle, "summary.tsv", sep = "_"), sep = "\t")

Step 4

Continue processing to identify significant genotypes.

## Determine significant genotypes
min.cl.pval <- 1e-12
min.diff.genes <- 40
ctrl.cl <- genotype.summary["mCherry", "min_cluster"]
sig.genotypes <- rownames(subset(genotype.summary, (abs(min_cluster_pval) < min.cl.pval & min_cluster != ctrl.cl) 
                                 | n_diff_genes > min.diff.genes))
sig.genotypes <- sort(unique(c(sig.genotypes, "mCherry-int-ctrl")), decreasing = T); print(sig.genotypes);
 [1] "TBX5"             "SNAI2"            "RUNX1"            "ONECUT1"          "NEUROG3"         
 [6] "NEUROG1"          "NEUROD1"          "MYOG"             "MYOD1"            "MYC"             
[11] "mCherry-int-ctrl" "KLF4"             "HNF1A"            "CDX2"             "ASCL4"           
[16] "ASCL1"           

Step 5

Generate barplot graph.

## Differential expression barplot
n.diff.genes <- genotype.summary[sig.genotypes, "n_diff_genes"]
names(n.diff.genes) <- sig.genotypes
gg.bar <- ggBarplot(n.diff.genes, fill.color = "purple")

# pdf(paste(file.handle, "diff_genes_barplot.pdf", sep = "_"), width = 3.5, height = 1.5)
# print(gg.bar)
# dev.off()

## Cluster enrichment heatmap (Figure 1c-e)
max.lp <- 50

genotypes.cl.lp <- apply(genotypes.cl.pvals[sig.genotypes,], 1:2, function(x) ifelse(x > 0, -log10(x), log10(-1 * x)))
genotypes.cl.lp[genotypes.cl.lp > max.lp] <- max.lp
genotypes.cl.lp[genotypes.cl.lp < -1 * max.lp] <- -1 * max.lp

# pdf(paste(file.handle, "cl_enrich_heatmap.pdf", sep = "_"), width = 4.5, height = 5)
# ggHeat(genotypes.cl.lp, clustering = "none", x.lab.size = 14, y.lab.size = 14)
# dev.off()

gg.heat <- ggHeat(t(genotypes.cl.lp), clustering = "none", x.lab.size = 14, y.lab.size = 14)
gg.bar <- gg.bar + theme(axis.text.x = element_blank())
gg.heat <- gg.heat + theme(legend.position = "none")

gg.1 <- ggplotGrob(gg.heat)
gg.2 <- ggplotGrob(gg.bar)

gg.aligned <- rbind(gg.2, gg.1, size = "first")
gg.aligned$widths <- grid::unit.pmax(gg.1$widths, gg.2$widths)

#pdf(paste(file.handle, "stacked_diff_genes_cl_enrich_nolabels.pdf", sep = "_"), width = 5.5, height = 6)
grid::grid.newpage()

grid::grid.draw(gg.aligned)

#dev.off()

Step 6

Generate tSNE plots

## tSNE plots (Figure 1c-e)
plot.seed <- 32907098
tsne.emb <- Embeddings(object = r, reduction = "tsne")

#pdf(paste(file.handle, "tsne_plot.pdf", sep = "_"), width = 4, height = 4)
PlotDims(tsne.emb, sample.groups = clusters, pt.size = 0.75, alpha.plot = 0.5, label.size = 6, do.label = T,
         show.legend = F, seed = plot.seed)

#dev.off()

#pdf(paste(file.handle, "tsne_plot_nolabel.pdf", sep = "_"), width = 4, height = 4)
PlotDims(tsne.emb, sample.groups = clusters, pt.size = 0.75, alpha.plot = 0.5, label.size = 0, do.label = F,
         show.legend = F, seed = plot.seed)

#dev.off()

#pdf(paste(file.handle, "tsne_plot_batch.pdf", sep = "_"), width = 4, height = 4)
batch <- factor(r@meta.data$batch)
# names(batch) <- r@cell.names
names(batch) <- colnames(r)

batch <- batch[rownames(tsne.emb)]

PlotDims(tsne.emb, sample.groups = batch, pt.size = 1, alpha.plot = 0.5, label.size = 8, do.label = T,
         show.legend = F, seed = plot.seed)

#dev.off()


## tSNE plot overlay
# plot.seed <- 32907098
# tsne.emb <- Embeddings(object = r, reduction = "tsne")

TF <- "NEUROD1"

tf.groups <- as.character(clusters); names(tf.groups) <- names(clusters);
tf.groups[names(tf.groups) %in% genotypes.list[[TF]]] <- TF
tf.groups[!names(tf.groups) %in% genotypes.list[[TF]]] <- ""
tf.groups <- factor(tf.groups)

#pdf(paste0(file.handle, "_tsne_plot_", TF, ".pdf"), width = 3, height = 3)
PlotDims(tsne.emb, sample.groups = tf.groups, pt.size = 0.35, alpha.plot = 0.4, label.size = 0, do.label = T,
         show.legend = F, seed = plot.seed) + scale_color_manual(values = c("grey", "red")) + ggtitle(TF)

#dev.off()

Using UMAP visualization in the Seurat package

r <- RunUMAP(r, reduction = “pca”, dims = 1:10)

This is swne on the UMAP embeddings, which captures both the local and global dataset structure

Embeddings – Dimensional Reduction Cell Embeddings Accessor Function

umap.emb <- Embeddings(r, reduction = “umap”) PlotDims(umap.emb, sample.groups = clusters, pt.size = 0.75, alpha.plot = 0.5, label.size = 6, do.label = T, show.legend = F, seed = plot.seed)

These are the 3 types of dimensionality reduction we learned: UMAP, t-SNE, and PCA

Both UMAP and t-SNE identify high dimensional struture (i.e., nonlinear dimensionality reduction), visualizing cell clusters, although distances are generally not interpretable

PCA identifies structure through linear transformation and shows clusters of samples based on their similarity); distances are interpretable (i.e., linear dimensionality reduction )

DimPlot(r, reduction = “umap”) DimPlot(r, reduction = “tsne”) DimPlot(r, reduction = “pca”)


Load all libraries

library(FlowSOM) library(flowCore) library(Biobase) library(ggplot2) library(hexbin) library(viridis) library(ggExtra) library(RColorBrewer) library(MEM) library(tidyverse) library(Rtsne) library(uwot)


# Time ~1 min
set.seed(OVERALL_SEED)
# Run UMAP on all scaled surface markers

# the line below will run UMAP on the data set (to see help page for UMAP, type 
# "?UMAP -- enter" in console)

# you can view UMAP progress by opening up the console below
myumap <-
  umap(transformed.chosen.markers,  # input scaled data
       
       n_neighbors = 15,            # number of nearest neighbors to look at, 
                                    # scales with data set
       
       n_threads = 1,               # this makes UMAP reproducible
       verbose = TRUE)
umap.data = as.data.frame(myumap)

cat("\n\n...'run_UMAP' finished running")

Step 7

Generate UMAP plots

LS0tCnRpdGxlOiAiUGFyZWtoIHBhcGVyIGZpZ3VyZXMiCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgUm1kOiBkZWZhdWx0Ci0tLQoKIyMgQ29kZSB0byBwcm9jZXNzIFBhcmVraCBwYXBlciBkYXRhClRoaXMgY29kZSBpcyBhc3NlbWJsZWQgdG8gcGVyZm9ybSB0aGUgc3RlcHMgdG8gc3VtbWFyaXplIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyBhbmQgY2x1c3RlcnMgb2YgY2VsbHMuIFRoZSBwcm9jZXNzZWQgZGF0YSB3ZXJlIGRvd25sb2FkZWQgYW5kIHNhdmVkIGluIGBTRVVTU19wcm9jZXNzZWRfZGF0YWAuCgpUaGlzIGNhZGUgaGFzIGJlZW4gcHVsbGVkIGZyb20gaHR0cHM6Ly9naXRodWIuY29tL3lhbnd1MjAxNC9TRVVTUy1BbmFseXNpcyBhbmQgc3BlY2lmaWNhbGx5IGNvcGllZCBmcm9tIGBoRVNDX3N1bW1hcml6ZV9yZXN1bHRzLlJgCgpUaGUgZGF0YSBmb3IgY2VsbHMgY3VsdHVyZWQgaW4gdGhlIHBsdXJpcG90ZW50IHN0ZW0gY2VsbCBtZWRpdW0gaGFzIGJlZW4gcHV0IGludG8gYSBjb21wcmVzc2VkIGZpbGUgaW4gdGhlIEdvb2dsZSBEcml2ZS4gWW91IHNob3VsZCBiZSBhYmxlIHRvIGRvd25sb2FkIGl0IGZyb20gdGhlIGZvbGxvd2luZyBsaW5rOiBodHRwczovL2RyaXZlLmdvb2dsZS5jb20vb3Blbj9pZD0xOXFIc1JGTzRRd0hob3R4dXc3M01ZUkhCOENGWVBNM2MgYW5kIGV4dHJhY3QgdGhlIGZpbGVzIG9udG8geW91ciBsb2NhbCBjb21wdXRlci4gWW91IHdpbGwgYWxzbyBuZWVkIHRvIGNoYW5nZSB0aGUgYGZpbGUuaGFuZGxlYCBhcHByb3ByaWF0ZWx5IChzZWUgYmVsb3cpLgoKIyMjIyBOT1RFClRoZSBmb2xsb3dpbmcgcGFja2FnZXMgbXVzdCBiZSBpbnN0YWxsZWQgcHJpb3IgdG8gcnVubmluZyAobWFueSBuZWVkZWQgb25seSB0byBsb2FkIGBzd25lYCBwYWNrYWdlLiBVbmNvbW1lbnQgdG8gZXhlY3V0ZS4KCmBgYHtyLCByZXN1bHRzPUZBTFNFfQpnZXRQYWNrYWdlSWZOZWVkZWQgPC0gZnVuY3Rpb24ocGtnKSB7CiAgaWYgKCFyZXF1aXJlKHBrZywgY2hhcmFjdGVyLm9ubHk9VFJVRSwgcXVpZXRseSA9VFJVRSkpCiAgICBpbnN0YWxsLnBhY2thZ2VzKHBrZ3M9cGtnLCBkZXBlbmRlbmNpZXM9VFJVRSkKfQpnZXRCaW9jUGFja2FnZUlmTmVlZGVkIDwtIGZ1bmN0aW9uKHBrZywgdmVycyA9IE5VTEwpIHsKICBpZiAoIXJlcXVpcmUocGtnLCBjaGFyYWN0ZXIub25seT1UUlVFLCBxdWlldGx5ID1UUlVFKSkKICAgIEJpb2NNYW5hZ2VyOjppbnN0YWxsKHBrZ3M9cGtnLCB2ZXJzaW9uPXZlcnMpCn0KCmJjcGtncyA8LSBsaXN0KGxpc3QocGtnPSJCaW9jTWFuYWdlciIsdmVycz0iMy4xMCIpLAogICAgICAgICAgICAgICBsaXN0KHBrZz0iVHhEYi5Ic2FwaWVucy5VQ1NDLmhnMzgua25vd25HZW5lIix2ZXJzPSIzLjEwIiksCiAgICAgICAgICAgICAgIGxpc3QocGtnPSJvcmcuSHMuZWcuZGIiKSwKICAgICAgICAgICAgICAgbGlzdChwa2c9IkdPLmRiIiksCiAgICAgICAgICAgICAgIGxpc3QocGtnPSJxdmFsdWUiLCB2ZXJzPSIzLjEwIikKICAgICAgICAgICAgICAgKQoKaW52aXNpYmxlKGxhcHBseShiY3BrZ3MsIGZ1bmN0aW9uKHgpIAogICAgZG8uY2FsbChnZXRCaW9jUGFja2FnZUlmTmVlZGVkLCBhcmdzPXgpKSkKCnBrZ3MJPC0JYygiZGV2dG9vbHMiLCJ1d290IiwidW1hcCIsIlNldXJhdCIpCmludmlzaWJsZShzYXBwbHkocGtncyxnZXRQYWNrYWdlSWZOZWVkZWQpKQppZiAoIXJlcXVpcmUoIk5OTE0iKSkgCiAgZGV2dG9vbHM6Omluc3RhbGxfdmVyc2lvbigiTk5MTSIsIHZlcnNpb24gPSAiMC40LjMiKQppZiAoIXJlcXVpcmUoInN3bmUiKSkgCiAgZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJ5YW53dTIwMTQvc3duZSIpCmlmICghcmVxdWlyZSgicGVydHVyYkxNIikpIAogIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YigieWFud3UyMDE0L3BlcnR1cmJMTSIsIHVwZ3JhZGUgPSAibmV2ZXIiKQpgYGAKCiMjIyMgU3VtbWFyeSBvZiBzdGVwcyB0byBiZSBydW4KU2V0IHRoZSBgZmlsZS5oYW5kbGVgIHBhcmFtZXRlciB0byB0aGUgbmFtZSBvZiB0aGUgc2FtcGxlIHRvIGJlIGFuYWx5emVkICh0aGlzIGNhbiBpbmNsdWRlIGBwYXRoYCBpbmZvcm1hdGlvbiBpZiBkYXRhIG5vdCBpbiB0aGUgc2FtZSBkaXJlY3RvcnkgYXMgdGhpcyBmaWxlKS4gR2VuZXJhdGUgYSBzdW1tYXJ5IHRhYmxlIGZvciBlYWNoIHNhbXBsZSwgYXMgd2VsbCBhcyBjbHVzdGVyIGVucmljaG1lbnQgaGVhdG1hcHMsIHRTTkUgcGxvdHMsIGFuZCBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBiYXJwbG90cy4gCgpUaGUgYGhFU0NfcnVuX3JlZ3Jlc3Npb24uUmAgYW5kIGBoRVNDX3J1bl9jbHVzdGVyaW5nLlJgIG11c3QgaGF2ZSBiZWVuIHJ1biBvbiB0aGUgc2FtcGxlIGZpcnN0LiAoVGhpcyBoYXMgYWxyZWFkeSBiZWVuIGRvbmUgYnkgUGFyZWtoIGV0IGFsLikKCiMjIyMgU3RlcCAxCkxvYWQgYWxsIHJlcXVpcmVkIGxpYnJhcmllcy4KYGBge3J9CiMjIyMgQ3JlYXRlIHQtU05FIHBsb3RzLCBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBoZWF0bWFwcywgYW5kIGNsdXN0ZXIgZW5yaWNobWVudCBoZWF0bWFwcwpsaWJyYXJ5KHBlcnR1cmJMTSkKbGlicmFyeShzd25lKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShncmlkKQpsaWJyYXJ5KGd0YWJsZSkKbGlicmFyeSh1bWFwKQoKYGBgCiAKIyMjIyBTdGVwIDIKRGVmaW5lIGZpbGUgbG9jYXRpb25zIGFuZCBsb2FkIGRhdGEuIEV4YW1wbGUgYmVsb3cgaW5jbHVkZXMgcGF0aCBpbmZvcm1hdGlvbiBmb3IgbXkgY29tcHV0ZXIuIE11c3QgYmUgbW9kaWZpZWQgdG8gd29yayBhcHByb3ByaWF0ZWx5IG9uIHlvdXIgY29tcHV0ZXIuCgpgYGB7cn0KIyMgTmFtZSBvZiB0aGUgc2FtcGxlIHRvIGJlIGFuYWx5emVkCmZpbGUuaGFuZGxlIDwtICIvVXNlcnMvdmFnYW4vRG93bmxvYWRzL1BhcmVraF9wYXBlcl9kYXRhL3VwLXRmLXN0ZW0iCiNmaWxlLmhhbmRsZSA8LSAidXAtdGYtc3RlbSIKIyBmaWxlLmhhbmRsZSA8LSAidXAtdGYtZW5kbyIKIyBmaWxlLmhhbmRsZSA8LSAidXAtdGYtbXVsdGkiCiMgZmlsZS5oYW5kbGUgPC0gInVwLXRmLWtsZiIKIyBmaWxlLmhhbmRsZSA8LSAidXAtdGYtbXljIgojIGZpbGUuaGFuZGxlIDwtICJ1cC10Zi1uZXVyb24tbm9oeWdybyIKCiMjIExvYWQgcmVncmVzc2lvbiByZXN1bHRzCmNvZWZzLmRmIDwtIHJlYWQudGFibGUocGFzdGUoZmlsZS5oYW5kbGUsICJyZWdyZXNzaW9uLnB2YWxzLnRzdiIsIHNlcCA9ICJfIiksIHNlcCA9ICJcdCIsIAogICAgICAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFQsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQp0b3AuY29lZnMuZGYgPC0gc3Vic2V0KGNvZWZzLmRmLCBGRFIgPCAwLjA1ICYgYWJzKGNmKSA+IDAuMDI1KQpwcmludChzb3J0KHRhYmxlKHRvcC5jb2Vmcy5kZiRHcm91cCksIGRlY3JlYXNpbmcgPSBUKSkKCiMjIExvYWQgY2x1c3RlcmluZwpyIDwtIHJlYWRSRFMocGFzdGUoZmlsZS5oYW5kbGUsICJjbHVzdGVyaW5nLlJvYmoiLCBzZXAgPSAiXyIpKQoKCmNsdXN0ZXJzIDwtIHJAaWRlbnQ7IG5hbWVzKGNsdXN0ZXJzKSA8LSByQGNlbGwubmFtZXM7CmxldmVscyhjbHVzdGVycykgPC0gcGFzdGUoIkMiLCBsZXZlbHMoY2x1c3RlcnMpLCBzZXAgPSAiIikKY2x1c3RlcnMubGlzdCA8LSBVbmZsYXR0ZW5Hcm91cHMoY2x1c3RlcnMpCgojIHVwZGF0ZSB2MiBTZXVyYXQgb2JqZWN0IHRvIHYzCnIgPC0gVXBkYXRlU2V1cmF0T2JqZWN0KHIpCgojIyBMb2FkIGdlbm90eXBlcwojIGdlbm90eXBlcy5saXN0IDwtIFJlYWRHZW5vdHlwZXMoInVwLXRmLWtsZi1teWNfcGhlbm9fZGljdC5jc3YiKQpnZW5vdHlwZXMubGlzdCA8LSBSZWFkR2Vub3R5cGVzKHBhc3RlKGZpbGUuaGFuZGxlLCAicGhlbm9fZGljdC5jc3YiLCBzZXAgPSAiXyIpKQpnZW5vdHlwZXMubGlzdCA8LSBsYXBwbHkoZ2Vub3R5cGVzLmxpc3QsIGZ1bmN0aW9uKHgpIHhbeCAlaW4lIG5hbWVzKGNsdXN0ZXJzKV0pCmdlbm90eXBlcy5zaXplcyA8LSBzYXBwbHkoZ2Vub3R5cGVzLmxpc3QsIGxlbmd0aCkKYGBgCgojIyMjIFN0ZXAgMwpDYWxjdWxhdGUgZW5yaWNobWVudCBzY29yZXMgYW5kIHN1bW1hcml6ZSByZXN1bHRzLgpgYGB7cn0KIyMgIENhbGN1bGF0ZSBnZW5vdHlwZSBlbnJpY2htZW50Cmdlbm90eXBlcy5jbC50YmwgPC0gR2Vub3R5cGVDbHVzdGVyQ291bnRzKGdlbm90eXBlcy5saXN0LCBjbHVzdGVycy5saXN0KQpnZW5vdHlwZXMuY2wucHZhbHMgPC0gR2Vub3R5cGVDbHVzdGVyUHZhbHMoZ2Vub3R5cGVzLmNsLnRibCkKCmdlbm90eXBlcy5taW4ucCA8LSBhcHBseShnZW5vdHlwZXMuY2wucHZhbHMsIDEsIGZ1bmN0aW9uKHgpIG1pbihhYnMoeCkpICogbGVuZ3RoKHgpKQptZXRhcDo6c3VtbG9nKGdlbm90eXBlcy5taW4ucCkKCiMjIFN1bW1hcml6ZSBhbmFseXNpcyByZXN1bHRzCmdlbm90eXBlLmNvdW50cyA8LSBzb3J0KHRhYmxlKHRvcC5jb2Vmcy5kZiRHcm91cCksIGRlY3JlYXNpbmcgPSBUKQpnZW5vdHlwZS5jb3VudHMgPC0gZ2Vub3R5cGUuY291bnRzW25hbWVzKGdlbm90eXBlLmNvdW50cykgJWluJSByb3duYW1lcyhnZW5vdHlwZXMuY2wucHZhbHMpXQpnZW5vdHlwZS5hdmdfY2YgPC0gdGFwcGx5KHRvcC5jb2Vmcy5kZiRjZiwgdG9wLmNvZWZzLmRmJEdyb3VwLCBmdW5jdGlvbih4KSBtZWFuKGFicyh4KSkpW25hbWVzKGdlbm90eXBlLmNvdW50cyldCgpnZW5vdHlwZS5zdW1tYXJ5IDwtIGRhdGEuZnJhbWUobl9kaWZmX2dlbmVzID0gYXMuaW50ZWdlcihnZW5vdHlwZS5jb3VudHMpLCBhdmdfY2YgPSBnZW5vdHlwZS5hdmdfY2YpCmdlbm90eXBlLnN1bW1hcnkkbWluX2NsdXN0ZXJfcHZhbCA8LSBhcHBseShnZW5vdHlwZXMuY2wucHZhbHNbcm93bmFtZXMoZ2Vub3R5cGUuc3VtbWFyeSksIF0sIDEsIGZ1bmN0aW9uKHgpIG1pbihhYnMoeCkpKQpnZW5vdHlwZS5zdW1tYXJ5JG1pbl9jbHVzdGVyIDwtIGFwcGx5KGdlbm90eXBlcy5jbC5wdmFsc1tyb3duYW1lcyhnZW5vdHlwZS5zdW1tYXJ5KSwgXSwgMSwgZnVuY3Rpb24oeCkgbmFtZXMoeFt3aGljaC5taW4oYWJzKHgpKV0pKQpnZW5vdHlwZS5zdW1tYXJ5JG5fY2VsbHMgPC0gZ2Vub3R5cGVzLnNpemVzW3Jvd25hbWVzKGdlbm90eXBlLnN1bW1hcnkpXQpgYGAKClVuY29tbWVudCBjb2RlIGJlbG93IGlmIHlvdSB3YW50IHRvIHNhdmUgdGhlIG91dHB1dCBkYXRhIHRvIGEgZmlsZS4KYGBge3J9CiMgd3JpdGUudGFibGUoZ2Vub3R5cGUuc3VtbWFyeSwgZmlsZSA9IHBhc3RlKGZpbGUuaGFuZGxlLCAic3VtbWFyeS50c3YiLCBzZXAgPSAiXyIpLCBzZXAgPSAiXHQiKQpgYGAKCiMjIyMgU3RlcCA0CkNvbnRpbnVlIHByb2Nlc3NpbmcgdG8gaWRlbnRpZnkgc2lnbmlmaWNhbnQgZ2Vub3R5cGVzLgpgYGB7cn0KIyMgRGV0ZXJtaW5lIHNpZ25pZmljYW50IGdlbm90eXBlcwptaW4uY2wucHZhbCA8LSAxZS0xMgptaW4uZGlmZi5nZW5lcyA8LSA0MApjdHJsLmNsIDwtIGdlbm90eXBlLnN1bW1hcnlbIm1DaGVycnkiLCAibWluX2NsdXN0ZXIiXQpzaWcuZ2Vub3R5cGVzIDwtIHJvd25hbWVzKHN1YnNldChnZW5vdHlwZS5zdW1tYXJ5LCAoYWJzKG1pbl9jbHVzdGVyX3B2YWwpIDwgbWluLmNsLnB2YWwgJiBtaW5fY2x1c3RlciAhPSBjdHJsLmNsKSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBuX2RpZmZfZ2VuZXMgPiBtaW4uZGlmZi5nZW5lcykpCnNpZy5nZW5vdHlwZXMgPC0gc29ydCh1bmlxdWUoYyhzaWcuZ2Vub3R5cGVzLCAibUNoZXJyeS1pbnQtY3RybCIpKSwgZGVjcmVhc2luZyA9IFQpOyBwcmludChzaWcuZ2Vub3R5cGVzKTsKYGBgCgojIyMjIFN0ZXAgNQpHZW5lcmF0ZSBiYXJwbG90IGdyYXBoLgpgYGB7cn0KIyMgRGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYmFycGxvdApuLmRpZmYuZ2VuZXMgPC0gZ2Vub3R5cGUuc3VtbWFyeVtzaWcuZ2Vub3R5cGVzLCAibl9kaWZmX2dlbmVzIl0KbmFtZXMobi5kaWZmLmdlbmVzKSA8LSBzaWcuZ2Vub3R5cGVzCmdnLmJhciA8LSBnZ0JhcnBsb3Qobi5kaWZmLmdlbmVzLCBmaWxsLmNvbG9yID0gInB1cnBsZSIpCgojIHBkZihwYXN0ZShmaWxlLmhhbmRsZSwgImRpZmZfZ2VuZXNfYmFycGxvdC5wZGYiLCBzZXAgPSAiXyIpLCB3aWR0aCA9IDMuNSwgaGVpZ2h0ID0gMS41KQojIHByaW50KGdnLmJhcikKIyBkZXYub2ZmKCkKCiMjIENsdXN0ZXIgZW5yaWNobWVudCBoZWF0bWFwIChGaWd1cmUgMWMtZSkKbWF4LmxwIDwtIDUwCgpnZW5vdHlwZXMuY2wubHAgPC0gYXBwbHkoZ2Vub3R5cGVzLmNsLnB2YWxzW3NpZy5nZW5vdHlwZXMsXSwgMToyLCBmdW5jdGlvbih4KSBpZmVsc2UoeCA+IDAsIC1sb2cxMCh4KSwgbG9nMTAoLTEgKiB4KSkpCmdlbm90eXBlcy5jbC5scFtnZW5vdHlwZXMuY2wubHAgPiBtYXgubHBdIDwtIG1heC5scApnZW5vdHlwZXMuY2wubHBbZ2Vub3R5cGVzLmNsLmxwIDwgLTEgKiBtYXgubHBdIDwtIC0xICogbWF4LmxwCgojIHBkZihwYXN0ZShmaWxlLmhhbmRsZSwgImNsX2VucmljaF9oZWF0bWFwLnBkZiIsIHNlcCA9ICJfIiksIHdpZHRoID0gNC41LCBoZWlnaHQgPSA1KQojIGdnSGVhdChnZW5vdHlwZXMuY2wubHAsIGNsdXN0ZXJpbmcgPSAibm9uZSIsIHgubGFiLnNpemUgPSAxNCwgeS5sYWIuc2l6ZSA9IDE0KQojIGRldi5vZmYoKQoKZ2cuaGVhdCA8LSBnZ0hlYXQodChnZW5vdHlwZXMuY2wubHApLCBjbHVzdGVyaW5nID0gIm5vbmUiLCB4LmxhYi5zaXplID0gMTQsIHkubGFiLnNpemUgPSAxNCkKZ2cuYmFyIDwtIGdnLmJhciArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKQpnZy5oZWF0IDwtIGdnLmhlYXQgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpnZy4xIDwtIGdncGxvdEdyb2IoZ2cuaGVhdCkKZ2cuMiA8LSBnZ3Bsb3RHcm9iKGdnLmJhcikKCmdnLmFsaWduZWQgPC0gcmJpbmQoZ2cuMiwgZ2cuMSwgc2l6ZSA9ICJmaXJzdCIpCmdnLmFsaWduZWQkd2lkdGhzIDwtIGdyaWQ6OnVuaXQucG1heChnZy4xJHdpZHRocywgZ2cuMiR3aWR0aHMpCgojcGRmKHBhc3RlKGZpbGUuaGFuZGxlLCAic3RhY2tlZF9kaWZmX2dlbmVzX2NsX2VucmljaF9ub2xhYmVscy5wZGYiLCBzZXAgPSAiXyIpLCB3aWR0aCA9IDUuNSwgaGVpZ2h0ID0gNikKZ3JpZDo6Z3JpZC5uZXdwYWdlKCkKZ3JpZDo6Z3JpZC5kcmF3KGdnLmFsaWduZWQpCiNkZXYub2ZmKCkKCmBgYAoKIyMjIyBTdGVwIDYKR2VuZXJhdGUgdFNORSBwbG90cwpgYGB7cn0KIyMgdFNORSBwbG90cyAoRmlndXJlIDFjLWUpCnBsb3Quc2VlZCA8LSAzMjkwNzA5OAp0c25lLmVtYiA8LSBFbWJlZGRpbmdzKG9iamVjdCA9IHIsIHJlZHVjdGlvbiA9ICJ0c25lIikKCiNwZGYocGFzdGUoZmlsZS5oYW5kbGUsICJ0c25lX3Bsb3QucGRmIiwgc2VwID0gIl8iKSwgd2lkdGggPSA0LCBoZWlnaHQgPSA0KQpQbG90RGltcyh0c25lLmVtYiwgc2FtcGxlLmdyb3VwcyA9IGNsdXN0ZXJzLCBwdC5zaXplID0gMC43NSwgYWxwaGEucGxvdCA9IDAuNSwgbGFiZWwuc2l6ZSA9IDYsIGRvLmxhYmVsID0gVCwKICAgICAgICAgc2hvdy5sZWdlbmQgPSBGLCBzZWVkID0gcGxvdC5zZWVkKQojZGV2Lm9mZigpCgojcGRmKHBhc3RlKGZpbGUuaGFuZGxlLCAidHNuZV9wbG90X25vbGFiZWwucGRmIiwgc2VwID0gIl8iKSwgd2lkdGggPSA0LCBoZWlnaHQgPSA0KQpQbG90RGltcyh0c25lLmVtYiwgc2FtcGxlLmdyb3VwcyA9IGNsdXN0ZXJzLCBwdC5zaXplID0gMC43NSwgYWxwaGEucGxvdCA9IDAuNSwgbGFiZWwuc2l6ZSA9IDAsIGRvLmxhYmVsID0gRiwKICAgICAgICAgc2hvdy5sZWdlbmQgPSBGLCBzZWVkID0gcGxvdC5zZWVkKQojZGV2Lm9mZigpCgojcGRmKHBhc3RlKGZpbGUuaGFuZGxlLCAidHNuZV9wbG90X2JhdGNoLnBkZiIsIHNlcCA9ICJfIiksIHdpZHRoID0gNCwgaGVpZ2h0ID0gNCkKYmF0Y2ggPC0gZmFjdG9yKHJAbWV0YS5kYXRhJGJhdGNoKQojIG5hbWVzKGJhdGNoKSA8LSByQGNlbGwubmFtZXMKbmFtZXMoYmF0Y2gpIDwtIGNvbG5hbWVzKHIpCgpiYXRjaCA8LSBiYXRjaFtyb3duYW1lcyh0c25lLmVtYildCgpQbG90RGltcyh0c25lLmVtYiwgc2FtcGxlLmdyb3VwcyA9IGJhdGNoLCBwdC5zaXplID0gMSwgYWxwaGEucGxvdCA9IDAuNSwgbGFiZWwuc2l6ZSA9IDgsIGRvLmxhYmVsID0gVCwKICAgICAgICAgc2hvdy5sZWdlbmQgPSBGLCBzZWVkID0gcGxvdC5zZWVkKQojZGV2Lm9mZigpCgoKIyMgdFNORSBwbG90IG92ZXJsYXkKIyBwbG90LnNlZWQgPC0gMzI5MDcwOTgKIyB0c25lLmVtYiA8LSBFbWJlZGRpbmdzKG9iamVjdCA9IHIsIHJlZHVjdGlvbiA9ICJ0c25lIikKClRGIDwtICJORVVST0QxIgoKdGYuZ3JvdXBzIDwtIGFzLmNoYXJhY3RlcihjbHVzdGVycyk7IG5hbWVzKHRmLmdyb3VwcykgPC0gbmFtZXMoY2x1c3RlcnMpOwp0Zi5ncm91cHNbbmFtZXModGYuZ3JvdXBzKSAlaW4lIGdlbm90eXBlcy5saXN0W1tURl1dXSA8LSBURgp0Zi5ncm91cHNbIW5hbWVzKHRmLmdyb3VwcykgJWluJSBnZW5vdHlwZXMubGlzdFtbVEZdXV0gPC0gIiIKdGYuZ3JvdXBzIDwtIGZhY3Rvcih0Zi5ncm91cHMpCgojcGRmKHBhc3RlMChmaWxlLmhhbmRsZSwgIl90c25lX3Bsb3RfIiwgVEYsICIucGRmIiksIHdpZHRoID0gMywgaGVpZ2h0ID0gMykKUGxvdERpbXModHNuZS5lbWIsIHNhbXBsZS5ncm91cHMgPSB0Zi5ncm91cHMsIHB0LnNpemUgPSAwLjM1LCBhbHBoYS5wbG90ID0gMC40LCBsYWJlbC5zaXplID0gMCwgZG8ubGFiZWwgPSBULAogICAgICAgICBzaG93LmxlZ2VuZCA9IEYsIHNlZWQgPSBwbG90LnNlZWQpICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImdyZXkiLCAicmVkIikpICsgZ2d0aXRsZShURikKI2Rldi5vZmYoKQpgYGAKCiMjIFVzaW5nIFVNQVAgdmlzdWFsaXphdGlvbiBpbiB0aGUgU2V1cmF0IHBhY2thZ2UgCnIgPC0gUnVuVU1BUChyLCByZWR1Y3Rpb24gPSAicGNhIiwgZGltcyA9IDE6MTApCgojIyBUaGlzIGlzIHN3bmUgb24gdGhlIFVNQVAgZW1iZWRkaW5ncywgd2hpY2ggY2FwdHVyZXMgYm90aCB0aGUgbG9jYWwgYW5kIGdsb2JhbCBkYXRhc2V0IHN0cnVjdHVyZSAKIyMgRW1iZWRkaW5ncyAtLSBEaW1lbnNpb25hbCBSZWR1Y3Rpb24gQ2VsbCBFbWJlZGRpbmdzIEFjY2Vzc29yIEZ1bmN0aW9uCnVtYXAuZW1iIDwtIEVtYmVkZGluZ3MociwgcmVkdWN0aW9uID0gInVtYXAiKQpQbG90RGltcyh1bWFwLmVtYiwgc2FtcGxlLmdyb3VwcyA9IGNsdXN0ZXJzLCBwdC5zaXplID0gMC43NSwgYWxwaGEucGxvdCA9IDAuNSwgbGFiZWwuc2l6ZSA9IDYsIGRvLmxhYmVsID0gVCwgc2hvdy5sZWdlbmQgPSBGLCBzZWVkID0gcGxvdC5zZWVkKSAKCiMjIFRoZXNlIGFyZSB0aGUgMyB0eXBlcyBvZiBkaW1lbnNpb25hbGl0eSByZWR1Y3Rpb24gd2UgbGVhcm5lZDogVU1BUCwgdC1TTkUsIGFuZCBQQ0EgCiMjIEJvdGggVU1BUCBhbmQgdC1TTkUgaWRlbnRpZnkgaGlnaCBkaW1lbnNpb25hbCBzdHJ1dHVyZSAoaS5lLiwgbm9ubGluZWFyIGRpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbiksIHZpc3VhbGl6aW5nIGNlbGwgY2x1c3RlcnMsIGFsdGhvdWdoIGRpc3RhbmNlcyBhcmUgZ2VuZXJhbGx5IG5vdCBpbnRlcnByZXRhYmxlCiMjIFBDQSBpZGVudGlmaWVzIHN0cnVjdHVyZSB0aHJvdWdoIGxpbmVhciB0cmFuc2Zvcm1hdGlvbiBhbmQgc2hvd3MgY2x1c3RlcnMgb2Ygc2FtcGxlcyBiYXNlZCBvbiB0aGVpciBzaW1pbGFyaXR5KTsgZGlzdGFuY2VzIGFyZSBpbnRlcnByZXRhYmxlIChpLmUuLCBsaW5lYXIgZGltZW5zaW9uYWxpdHkgcmVkdWN0aW9uICkgCkRpbVBsb3QociwgcmVkdWN0aW9uID0gInVtYXAiKQpEaW1QbG90KHIsIHJlZHVjdGlvbiA9ICJ0c25lIikKRGltUGxvdChyLCByZWR1Y3Rpb24gPSAicGNhIikKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMjIExvYWQgYWxsIGxpYnJhcmllcwpsaWJyYXJ5KEZsb3dTT00pCmxpYnJhcnkoZmxvd0NvcmUpCmxpYnJhcnkoQmlvYmFzZSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGhleGJpbikKbGlicmFyeSh2aXJpZGlzKQpsaWJyYXJ5KGdnRXh0cmEpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KE1FTSkKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoUnRzbmUpCmxpYnJhcnkodXdvdCkKCmBgYHtyIHJ1bl9VTUFQfQoKIyBUaW1lIH4xIG1pbgpzZXQuc2VlZChPVkVSQUxMX1NFRUQpCiMgUnVuIFVNQVAgb24gYWxsIHNjYWxlZCBzdXJmYWNlIG1hcmtlcnMKCiMgdGhlIGxpbmUgYmVsb3cgd2lsbCBydW4gVU1BUCBvbiB0aGUgZGF0YSBzZXQgKHRvIHNlZSBoZWxwIHBhZ2UgZm9yIFVNQVAsIHR5cGUgCiMgIj9VTUFQIC0tIGVudGVyIiBpbiBjb25zb2xlKQoKIyB5b3UgY2FuIHZpZXcgVU1BUCBwcm9ncmVzcyBieSBvcGVuaW5nIHVwIHRoZSBjb25zb2xlIGJlbG93Cm15dW1hcCA8LQogIHVtYXAodHJhbnNmb3JtZWQuY2hvc2VuLm1hcmtlcnMsICAjIGlucHV0IHNjYWxlZCBkYXRhCiAgICAgICAKICAgICAgIG5fbmVpZ2hib3JzID0gMTUsICAgICAgICAgICAgIyBudW1iZXIgb2YgbmVhcmVzdCBuZWlnaGJvcnMgdG8gbG9vayBhdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgc2NhbGVzIHdpdGggZGF0YSBzZXQKICAgICAgIAogICAgICAgbl90aHJlYWRzID0gMSwgICAgICAgICAgICAgICAjIHRoaXMgbWFrZXMgVU1BUCByZXByb2R1Y2libGUKICAgICAgIHZlcmJvc2UgPSBUUlVFKQp1bWFwLmRhdGEgPSBhcy5kYXRhLmZyYW1lKG15dW1hcCkKCmNhdCgiXG5cbi4uLidydW5fVU1BUCcgZmluaXNoZWQgcnVubmluZyIpCgpgYGAKCiMjIyBTdGVwIDcgCkdlbmVyYXRlIFVNQVAgcGxvdHMg